import pandas as pd
import numpy as np
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.metrics.pairwise import cosine_similarity
import matplotlib.pyplot as plt

# 电影内容数据（含类型、导演、演员等特征）
movies = pd.DataFrame({
    'movie_id': [1, 2, 3, 4, 5],
    'title': ['银翼杀手2049', '沙丘', '星际穿越', '泰坦尼克号', '罗马假日'],
    'genres': ['科幻/悬疑', '科幻/冒险', '科幻/剧情', '爱情/灾难', '爱情/喜剧'],
    'director': ['丹尼斯·维伦纽瓦', '丹尼斯·维伦纽瓦', '克里斯托弗·诺兰', '詹姆斯·卡梅隆', '威廉·惠勒'],
    'actors': ['瑞恩·高斯林', '提莫西·查拉梅', '马修·麦康纳', '莱昂纳多·迪卡普里奥', '格利高里·派克']
})

# 用户评分数据（模拟5个用户对部分电影的评分，1-5分）
ratings = pd.DataFrame({
    'user_id': [1, 1, 2, 2, 3, 3, 4, 5, 5],
    'movie_id': [1, 3, 2, 4, 1, 5, 3, 2, 4],
    'rating': [4, 5, 3, 5, 2, 4, 5, 4, 3]
})

# 合并电影与评分数据，生成用户-电影评分矩阵
user_movie_matrix = ratings.pivot_table(index='user_id', columns='movie_id', values='rating', fill_value=0)

# 提取电影内容特征（拼接类型、导演、演员为文本）
movies['features'] = movies['genres'] + ' ' + movies['director'] + ' ' + movies['actors']
vectorizer = TfidfVectorizer(stop_words='english')
movie_features = vectorizer.fit_transform(movies['features'])

# 1. 基于内容的推荐：计算电影相似度
movie_similarity = cosine_similarity(movie_features)

# 2. 基于用户的协同过滤：计算用户相似度
user_similarity = cosine_similarity(user_movie_matrix)


# 3. 混合推荐：为用户1生成推荐（假设用户ID=1）
def hybrid_recommendation(user_id, top_n=3):
    # 获取用户评分记录
    user_ratings = user_movie_matrix.loc[user_id]
    liked_movies = user_ratings[user_ratings > 3].index  # 筛选评分>3的电影

    # 基于内容推荐：扩展相似电影
    content_recommendations = []
    for movie in liked_movies:
        similar_indices = np.argsort(movie_similarity[movie - 1])[::-1][1:4]  # 取前3个相似电影（排除自身）
        content_recommendations.extend(movies.iloc[similar_indices]['movie_id'])

    # 基于用户协同过滤：找相似用户的高评分电影
    user_neighbors = np.argsort(user_similarity[user_id - 1])[::-1][1:3]  # 取前2个相似用户
    cf_recommendations = []
    for neighbor in user_neighbors:
        neighbor_ratings = user_movie_matrix.iloc[neighbor]
        high_rated = neighbor_ratings[neighbor_ratings > 4].index
        cf_recommendations.extend(high_rated)

    # 混合推荐结果（去重并按出现次数排序）
    combined = content_recommendations + cf_recommendations
    recommendation_counts = pd.Series(combined).value_counts()
    top_recommendations = recommendation_counts[~recommendation_counts.index.isin(liked_movies)].index[:top_n]

    return top_recommendations


# 生成推荐（用户1的推荐结果）
recommended_movie_ids = hybrid_recommendation(user_id=1)
recommended_movies = movies[movies['movie_id'].isin(recommended_movie_ids)]

print("为用户1推荐的电影：")
print(recommended_movies[['title', 'genres', 'director']])

# 设置中文字体
plt.rcParams["font.family"] = ["SimHei"]
plt.rcParams['axes.unicode_minus'] = False  # 解决负号显示问题

# 绘制用户评分分布直方图
plt.figure(figsize=(8, 4))
plt.subplot(1, 2, 1)
ratings['rating'].hist(bins=5, color='skyblue', edgecolor='black')
plt.title('用户评分分布')
plt.xlabel('评分')
plt.ylabel('次数')

# 绘制电影类型分布饼图
movie_genres = movies['genres'].str.split('/').explode()
genre_counts = movie_genres.value_counts()
plt.subplot(1, 2, 2)
genre_counts.plot.pie(autopct='%1.1f%%', startangle=90)
plt.title('电影类型分布')
plt.axis('equal')  # 保证饼图为圆形
plt.tight_layout()
plt.show()